package com.thug.engine;

import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.Stack;

import org.anddev.andengine.engine.Engine;
import org.anddev.andengine.engine.camera.Camera;
import org.anddev.andengine.engine.camera.ZoomCamera;
import org.anddev.andengine.engine.options.EngineOptions;
import org.anddev.andengine.engine.options.EngineOptions.ScreenOrientation;
import org.anddev.andengine.engine.options.resolutionpolicy.RatioResolutionPolicy;
import org.anddev.andengine.entity.scene.Scene;
import org.anddev.andengine.extension.physics.box2d.FixedStepPhysicsWorld;
import org.anddev.andengine.extension.physics.box2d.PhysicsWorld;
import org.anddev.andengine.ui.activity.BaseGameActivity;

import android.view.Display;

import com.badlogic.gdx.math.Vector2;


public abstract class SceneManager extends BaseGameActivity
{
	//private:
	private Stack<SceneState> mStates;
	private PhysicsWorld mWorld;
	private Map<String, Object> mResourceCache;

	private Camera mCamera;
	private SceneState mCurrentState;

	private int mWidth, mHeight;
	private ScreenOrientation mOrient;
	private boolean mFullscreen;
	private boolean mSoundNeeded;

	private float mTimeDilation;
	public static final float PIXEL_TO_METER_RATIO = 32;


	//public:
	public static final int DEF_RES_CACHE_SIZE = 1000;

	public SceneManager(ScreenOrientation so, boolean fullscreen, boolean sound, int cache_size)
	{
		mStates = new Stack<SceneState>();
		mResourceCache = Collections.synchronizedMap(new HashMap<String, Object>(cache_size));

		setCamera(null);

		mWidth = mHeight = -1;
		mOrient = so;
		mFullscreen = fullscreen;
		mSoundNeeded = sound;

		setTimeDilation(1.0f);
	}

	public PhysicsWorld getPhysicsWorld() { return mWorld; }

	public Camera getCamera() { return mCamera; }
	public void setCamera(Camera c) { mCamera = c; }

	public int getScreenWidth() { return mWidth; }
	public int getScreenHeight() { return mHeight; }

	public float getTimeDilation() { return mTimeDilation; }
	public void setTimeDilation(float t) { mTimeDilation = t; }

	public Scene getScene() { return (Scene)mCurrentState; }

	/** RESOURCE CACHE STUFF **/
	// Store any 'res' under the key 'id'. Do not allow matching 'id's
	public Object addResource(String id, Object res)
	{
		//if (mResourceCache.containsKey(id))
			//throw new IllegalStateException("ERROR: Resource Cache already has resource with an ID of '" + id + "'");

		mResourceCache.put(id, res);
		return res;
	}
	// Return Object from the cache with the same 'id'. Null if no Object with matching 'id' is found
	public Object getResource(String id)
	{
		return mResourceCache.get(id);
	}
	// Returns true if resource with matching 'id' was removed.
	public boolean removeResource(String id)
	{
		return (mResourceCache.remove(id) != null);
	}


	/** STATE MACHINE STUFF **/
	// Ends the current state, starts the new one.
	public final void changeState(final SceneState new_state)
	{
		mCurrentState = new_state;
		// destroy the current state
		if (!mStates.empty())
			mStates.pop().onDestroy();

		// store and init the new state
		mStates.push(mCurrentState);
		mStates.peek().onLoad();
		getEngine().setScene(mStates.peek());

	}

	// Pauses the current state, starts the new one.
	public final void pushState(final SceneState new_state)
	{
		mCurrentState = new_state;

		// pause current state
		if (!mStates.empty())
			mStates.peek().onPause();

		// store and init the new state
		mStates.push(mCurrentState);
		mStates.peek().onLoad();
		getEngine().setScene(mStates.peek());

	}

	// Ends the current state, resumes the previous state
	public final void popState()
	{
		// cleanup the current state
		if (!mStates.empty())
			mStates.pop().onDestroy();

		// resume previous state
		if ( !mStates.empty() )
		{
			mCurrentState = mStates.peek();
			mStates.peek().onResume();
			getEngine().setScene(mStates.peek());
		}

	}

	// Ends all states.
	public final void clearStates()
	{
		while (!mStates.empty())
			popState();

		getEngine().setScene(null);
	}



	/** ENGINE STUFF **/
	@Override // Override this in subclass to use different Engine type or display dimensions
	public Engine onLoadEngine()
	{
		final Display display = getWindowManager().getDefaultDisplay();
		mWidth = display.getWidth();
		mHeight = display.getHeight();
		
		mWorld = new FixedStepPhysicsWorld(30, new Vector2(0, 0), false, 3, 2);


		//setCamera(new Camera(0, 0, getScreenWidth(), getScreenHeight()));
		//mCamera = new SmoothCamera(0, 0, getScreenWidth(), getScreenHeight(), 10, 10, 1.0f);
		mCamera = new ZoomCamera(0, 0, getScreenWidth()*2, getScreenHeight()*2);

		final EngineOptions engineOptions = new EngineOptions(mFullscreen, mOrient, new RatioResolutionPolicy(getScreenWidth(), getScreenHeight()), mCamera);
		engineOptions.getTouchOptions().setRunOnUpdateThread(true);
		engineOptions.setNeedsSound(mSoundNeeded);
		engineOptions.setNeedsMusic(mSoundNeeded);

		return new Engine(engineOptions);
	}

	@Override
	public void onLoadResources() {}

	@Override
	public Scene onLoadScene() { return null; }
}
